package cn.edu.swu.miniwebsvr.handler;

import cn.edu.swu.miniwebsvr.core.Config;
import cn.edu.swu.miniwebsvr.core.Handler;
import cn.edu.swu.miniwebsvr.core.Parameter;


import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class DefaultHandler implements Handler {
    @Override
    public void handle(Parameter request, OutputStream response) {
        // [222024321072041/王耀东]
        // 1. 获取请求路径（可能需要将 / 映射到 index.html）
        // 2. 根据 Config.getWebRoot() 构建完整文件路径
        Path filePath = Paths.get(Config.getInstance().getWenRoot(),
                request.getUrl().equals("/") ? "index.html" :request.getUrl().substring(1)).normalize();

        try{
            // 安全检查：确保请求的文件在WEB_ROOT目录下，防止目录遍历攻击
            if (!filePath.startsWith(Paths.get(Config.getInstance().getWenRoot()))) {
                try {
                    String errorResponse = "HTTP/1.1 403 Forbidden\r\n" +
                            "Content-Type: text/html\r\n" +
                            "\r\n" +
                            "<html><body><h1>" +"500 Internal Server Error" + "</h1></body></html>";
                    response.write(errorResponse.getBytes(StandardCharsets.UTF_8));
                    response.flush();
                } catch (IOException e){
                    e.printStackTrace();
                }
            }

            if (Files.exists(filePath) && !Files.isDirectory(filePath)) {
                // 读取文件内容到字节数组，并不区分是什么文件；这里是把文件全部读到内存里了，要是需要传输大的文件，一定要设置缓冲区
                byte[] fileBytes = Files.readAllBytes(filePath);
                // [222024321072041/王耀东] 确定并设置正确的 Content-Type (例如 text/html, image/jpeg 等)
                // 发送HTTP响应头。告诉用户浏览器如何处理这些数据包
                String contentType = getContentType(filePath);
                
                // 构造并写入返回的HTTP协议! 状态码200：成功; 每一段最后要有换行（\r\n,为兼容windows）
                response.write(("HTTP/1.1 200 OK\r\n").getBytes());
                response.write(("Content-Type: " + contentType + "\r\n").getBytes());
                response.write(("Content-Length: " + fileBytes.length + "\r\n").getBytes());
                response.write(("\r\n").getBytes());
                // 写入文件内容
                response.write(fileBytes);
                response.flush();

            } else {
                // 文件不存在或路径错误，返回 404
                String content = "<h1>404 Not Found</h1><p>The requested resource " + request.getUrl() + " was not found.</p>";
                response.write(("HTTP/1.1 404 Not Found\r\n").getBytes());
                response.write(("Content-Type: text/html; charset=UTF-8\r\n").getBytes());
                response.write(("Content-Length: " + content.getBytes().length + "\r\n").getBytes());
                response.write(("\r\n").getBytes());
                response.write(content.getBytes());
            }
        }catch (IOException e) {
            try {
                String errorResponse = "HTTP/1.1 500 Internal Server Error\r\n" +
                        "Content-Type: text/html\r\n" +
                        "\r\n" +
                        "<html><body><h1>" + "500 Internal Server Error" + "</h1></body></html>";
                response.write(errorResponse.getBytes(StandardCharsets.UTF_8));
                response.flush();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        } finally {
            try {
                response.flush();
            } catch (IOException e) { /* ignore */ }
        }




    }

    private static String getContentType(Path filePath) {
        String fileName = filePath.toString().toLowerCase();

        if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
            // 这些名称都是HTTP协议规定好的，不能乱改
            return "text/html";
        } else if (fileName.endsWith(".css")) {
            return "text/css";
        } else if (fileName.endsWith(".js")) {
            return "application/javascript";
        } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
            return "image/jpeg";
        } else if (fileName.endsWith(".png")) {
            return "image/png";
        } else if (fileName.endsWith(".gif")) {
            return "image/gif";
        } else {
            return "application/octet-stream";
        }
    }
}
